package lt.egidijus.aatest.popup.actions;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import lt.egidijus.aatest.BrowserView;
import lt.egidijus.aatest.listener.TestRunnerListener;
import lt.egidijus.aatest.utils.Constants;
import lt.egidijus.aatest.utils.Utils;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.PackageFragment;
import org.eclipse.jdt.junit.JUnitCore;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IActionDelegate;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleConstants;
import org.eclipse.ui.console.IConsoleManager;
import org.eclipse.ui.console.IConsoleView;
import org.eclipse.ui.console.MessageConsole;
import org.eclipse.ui.console.MessageConsoleStream;

public class CalculateCustomCoverageAction  implements IObjectActionDelegate {

	/**
	 * Constructor for Action1.
	 */
	public CalculateCustomCoverageAction() {
		super();
	}

	private Shell shell;

	/**
	 * @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart)
	 */
	public void setActivePart(IAction action, IWorkbenchPart targetPart) {
		shell = targetPart.getSite().getShell();
	}

	List<ICompilationUnit> list = new ArrayList<ICompilationUnit>(0);
	String generationTime = "";
	/**
	 * @see IActionDelegate#run(IAction)
	 */
	public void run(IAction action) {
		
		if (!Constants.clickTestProject){
			Display.getDefault().asyncExec(new Runnable() {
				public void run() {
					MessageDialog.openError(shell, "Coverage error", "Coverage can generate only test project!");
				}
			});
			return;
		}
		ProgressMonitorDialog dialog = new ProgressMonitorDialog(shell);
			try {
				dialog.run(true, true, new IRunnableWithProgress() {
					@Override
					public void run(IProgressMonitor monitor) {
						long t1 =  System.currentTimeMillis();
						monitor.beginTask("Generating coverage report..", 7);
						try{
							final String path = ResourcesPlugin.getWorkspace().getRoot().getLocation().toString();
							String updateMainProject = "android update project -p \"" + path +"/"+ Constants.projectName +"\"";
							String buildMainProject = "ant -f \"" + path +"/"+ Constants.projectName +"/build.xml\" clean debug";

							String updateProject = "android update test-project -m \"" + path +"/"+ Constants.projectName +"\" -p \"" + path +"/"+ Constants.testProjectName +"\"";
							String buildCoverageReport = "ant -f \"" + path +"/"+ Constants.testProjectName +"/build.xml\" all clean emma debug install test";
							String buildXMLReport = "java emma report -r xml -in \"" + path +"/"+ Constants.testProjectName +"/coverage/coverage.em\" -in \"" 
							+ path +"/"+ Constants.testProjectName +"/coverage/coverage.ec\"" + " -Dreport.xml.out.file=\""+path +"/"+ Constants.testProjectName +"/coverage/coverage.xml\"";

							monitor.subTask("Initialization..");
							monitor.worked(1);
							//String komanda = "ping google.com";
					        System.out.println(updateMainProject);
					        System.out.println(buildMainProject);
					       System.out.println(buildXMLReport);
					        System.out.println(updateProject);
					        System.out.println(buildCoverageReport);
					       System.out.println(buildXMLReport);
					        MessageConsole myConsole = findConsole("Coverage"); 
					        MessageConsoleStream out = myConsole.newMessageStream();
					        myConsole.activate();
							monitor.subTask("Update main project..");
					        boolean exitVal = commandLine(updateMainProject, out, monitor);
							monitor.worked(2);
//					        if (exitVal){
//								monitor.subTask("Build main project..");
//					        	exitVal = commandLine(buildMainProject, out, monitor);
//								monitor.worked(3);
//					        }
					        if (exitVal){
								monitor.subTask("Updating test project..");
								exitVal = commandLine(updateProject, out, monitor);
								monitor.worked(3);
					        }
					        if (exitVal){
								monitor.subTask("Building test project, running tests and generating report..");
					        	exitVal = commandLine(buildCoverageReport, out, monitor);
								monitor.worked(4);
					        }
					     //   if (exitVal){
						//		monitor.subTask("Generating xml report..");
					    //    	exitVal = commandLine(buildXMLReport, out, monitor);
						//		monitor.worked(4);
					    //   }
						//	boolean exitVal = true;
					        System.out.println("exitVal " +exitVal); 
					        monitor.done();
					        long t2 =  System.currentTimeMillis();
					        generationTime = String.format("\nExecution time -%8.2f s.", (t2 - t1)/1000.0);
					        if (exitVal){
								Display.getDefault().asyncExec(new Runnable() {
									public void run() {
										String message = "Coverage report generated successfully.";
										if (Constants.showTimes)
											message = message + generationTime;
										MessageDialog.openInformation(shell, "Coverage report", message);
										 IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
									     if (window != null) {
									    	 try {
									    	window.getActivePage().showView("AATestPlugin.coverageBrowser");
									    	BrowserView brview =  (BrowserView) window.getActivePage().findView("AATestPlugin.coverageBrowser");
									    	brview.setLocationUrl(path +"/"+ Constants.testProjectName+"/coverage/coverage.html", "Coverage report");
											window.getActivePage().showView("AATestPlugin.coverageBrowser");
											} catch (PartInitException e) {
												e.printStackTrace();
											}
									     }
									}
								});
					        }
					        else{
								Display.getDefault().asyncExec(new Runnable() {
									public void run() {
										MessageDialog.openError(shell, "Coverage report", "An errorr occured when generating coverage report. More info can be found in the logs.");
									}
								});
					        }    
				    } catch (Throwable t)
				      {
				        t.printStackTrace();
				      }

					}
				});
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
//		} catch (InvocationTargetException e) {
//			e.printStackTrace();
//		} catch (InterruptedException e) {
//			e.printStackTrace();
//		}
//		
//		Job job = new Job("My Job") {
//			@Override
//			protected IStatus run(IProgressMonitor monitor) {
//				
//	    
//								
//
//				return Status.OK_STATUS;
//			}
//		};
//		job.schedule();

//		IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(Constants.projectName);
//		JUnitFinder finder = new JUnitFinder();
//		ArrayList<ICompilationUnit> cList =  finder.findJUnitsForProject((JavaCore.create(project)));
//		AAtestList listtas = new AAtestList();
//		listtas.addList(cList);
//		IProject project2 = ResourcesPlugin.getWorkspace().getRoot().getProject(Constants.testProjectName);
//		ArrayList<ICompilationUnit> cList2 =  finder.findJUnitsForProject((JavaCore.create(project2)));
//		listtas.addList(cList2);
//		ArrayList<AAtestClass> randomTests = new ArrayList<AAtestClass>();
//		for (AAtestClass aClass : listtas.getList()){
//			if (aClass.getTestRandom() != null)
//				randomTests.add(aClass);
//		}
//		AAtestList randomList = new AAtestList();
//		randomList.setList(randomTests);	
//		RunCustomTestsWizard wizard = new RunCustomTestsWizard(shell,randomList);
//        TestsWizardDialog dialog = new TestsWizardDialog(shell, wizard);
//        dialog.create();
//        dialog.open();
//        if (wizard.getSelectedClassList()!= null){
//        	TestSuiteGenerator suiteGen = new TestSuiteGenerator();
// 			suiteGen.createTestSuite(wizard.getSelectedClassList());
// 			AATestJunitLauncher laucher = new AATestJunitLauncher();
//			Utils.deleteCoverageFolder();
//			Utils.createCoverageFolder();
//			laucher.setCoverageArgument("-javaagent:lib\\jacocoagent.jar=destfile="+Constants.coverageResourcesFolder+"\\coverage.log");
//			laucher.launchCustom(suiteGen.getGeneratedUnit(), "run");
//        }
//		

//		Semaphore sem = new Semaphore(2);
//		JUnitCore.addTestRunListener(new Listener(sem));
//		System.out.println(list.size());
//		while (true){
//		try {
//			sem.acquire();
//		} catch (InterruptedException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//		IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject("test");
//		
//	    StructuredSelection selection = new StructuredSelection(list);
//	    
//		JUnitLaunchShortcut launch = new JUnitLaunchShortcut();
//		launch.launch(selection, "run");
//		
//		}

	}
	
	private boolean commandLine(String command, MessageConsoleStream output, IProgressMonitor monitor ) throws InterruptedException, IOException{
		String[] cmd = new String[3];
        cmd[0] = "cmd.exe" ;
        cmd[1] = "/C" ;
        cmd[2] = command;
        Runtime rt = Runtime.getRuntime();
        Process proc = rt.exec(cmd);
        
        InputStreamReader is = new InputStreamReader(proc.getInputStream());
        BufferedReader br = new BufferedReader(is);   
        String line=null;
    	 int i =0;
		 while ( (line = br.readLine()) != null){
				i++;
		//		monitor.subTask("I'm doing something here " + i);
			    output.println("INFO> " + line); 
			//	monitor.worked(1);
			}
		  InputStreamReader isr = new InputStreamReader(proc.getErrorStream());
	      BufferedReader brr = new BufferedReader(isr);   
	      line=null;
	      int error =0;
	      while ( (line = brr.readLine()) != null){
	    	  	error++;
			    output.println("ERROR> " + line); 
				//monitor.worked(1);
		  }

         int exitVal = proc.waitFor();
         if (exitVal == 0 && error == 0)
        	 return true;
         return false;
	}
	
	
    private static MessageConsole findConsole(String name) {
	      ConsolePlugin plugin = ConsolePlugin.getDefault();
	      IConsoleManager conMan = plugin.getConsoleManager();
	      IConsole[] existing = conMan.getConsoles();
	      for (int i = 0; i < existing.length; i++)
	         if (name.equals(existing[i].getName()))
	            return (MessageConsole) existing[i];
	      //no console found, so create a new one
	      MessageConsole myConsole = new MessageConsole(name, null);
	      conMan.addConsoles(new IConsole[]{myConsole});
	      return myConsole;
  }

	public static void writeToConsole(String message) { 
		  MessageConsole myConsole = findConsole("Coverage log"); 
		  MessageConsoleStream out = myConsole.newMessageStream(); 
		  out.println(message);
		  // Make console visible 
		  IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); 
		  try { 
		    IConsoleView view = (IConsoleView) page.showView(IConsoleConstants.ID_CONSOLE_VIEW); 
		    view.display(myConsole); 
		  } catch (Exception e) { 
				e.printStackTrace(); 
		  } 
		}

	/**
	 * @see IActionDelegate#selectionChanged(IAction, ISelection)
	 */
	public void selectionChanged(IAction action, ISelection selection) {
		Utils.updateProjectsNames(selection);
		if (selection instanceof TreeSelection) {
			org.eclipse.jface.viewers.TreeSelection t = (TreeSelection) selection;
			Iterator<?> it = t.iterator();
			while (it.hasNext()) {
				Object o = it.next();
				if (o instanceof ICompilationUnit) {
					ICompilationUnit c = (ICompilationUnit) o;
					list.add(c);
				} else {
					if (o instanceof IPackageFragmentRoot) {
						IPackageFragmentRoot pack = (IPackageFragmentRoot) o;
						try {
							for (IJavaElement e : pack.getChildren()) {
								if (e instanceof PackageFragment) {
									PackageFragment p = (PackageFragment) e;
									list.addAll(Arrays.asList(p
											.getCompilationUnits()));
								}

							}
						} catch (JavaModelException e) {
							e.printStackTrace();
						}
					} else {
						if (o instanceof PackageFragment) {
							PackageFragment fragment = (PackageFragment) o;
							try {
								list.addAll(Arrays.asList(fragment
										.getCompilationUnits()));
							} catch (JavaModelException e) {
								e.printStackTrace();
							}

						}
					}
				}
			}
		}
	}
}